/*
 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
 * Licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
#include "se_main.h"
#include <securec.h>
#include <dlist.h>

#include "tee_log.h"
#include "tee_mem_mgmt_api.h"
#include "tee_defines.h"
#include "se_status.h"
#include "se_service.h"
#include "tee_ext_se_api.h"
#include "inse_ext.h"
#include "tee_dynamic_srv.h"
#include "tee_drv_client.h"

#define SE_SRV_SUCCESS             0
#define SE_SRV_ERROR               (-1)
#define MAGIC_STR_LEN              20
#define SE_CONNECT_FLAG            1
#define SE_DISCONNECT_FLAG         0
#define BASIC_CHANNEL_ID           0
#define LOGICAL_CHANNEL_MAX        20
#define READER_MAX                 6
#define LOGIC_CHANNEL_ID_OFFSET    4
#define GET_SEVENTH_BIT            0x40
#define SE_PERMISSION              0x01

#define LOG_TAG "se service"
#define SE_PATH "seservice"

TEE_Result se_service_check_msp_permission(const TEE_UUID *uuid);
bool is_msp_enable(void);
bool is_sec_flash_enable(void);
uint32_t get_vote_id(uint32_t reader_id, const TEE_UUID *uuid);

static uint32_t g_ta_channel[READER_MAX][LOGICAL_CHANNEL_MAX];
typedef TEE_Result (*cmd_func)(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                               uint32_t sndr_pid, const TEE_UUID *uuid);

struct cmd_check_config_s {
    uint32_t cmd_id;
    cmd_func check_func;
};

struct channel_info_t {
    uint32_t reader_id;
    uint8_t channel_id;
};

struct seaid_switch_srv_info {
    struct seaid_switch_info seaid_switch;
    struct dlist_node list;
};

struct se_connect_info {
    uint32_t sndr_pid;
    uint32_t connect_count;
    TEE_UUID uuid;
    struct dlist_node list;
};

struct dlist_node g_se_connect_info_head[READER_MAX];
struct dlist_node g_seaid_switch_head;
static uint8_t g_buf_sw_refused[] = {SW1_GP_REFUSE, SW2_GP_REFUSE};
static int32_t g_se_type = SE_SRV_ERROR;
/* g_se_deactive_flag is only effective for inSE&eSE */
static bool g_se_deactive_flag = false;

static int32_t se_srv_map_from_task(uint32_t in_task_id, uint64_t va_addr, uint32_t size,
                                    uint64_t *virt_addr)
{
    uint64_t vaddr;
    int32_t ret;

    ret = tee_srv_map_from_task(in_task_id, va_addr, size, (uint32_t *)(uintptr_t)&vaddr);
    if (ret == 0)
        *virt_addr = (uintptr_t)vaddr;

    return ret;
}

static void se_srv_task_unmap(uint64_t virt_addr, uint32_t size)
{
    if (virt_addr == 0)
        return;

    tee_srv_unmap_from_task(virt_addr, size);
}

static TEE_Result se_service_check_permission(const TEE_UUID *uuid)
{
    (void)uuid;
    return TEE_SUCCESS;
}

static TEE_Result check_permission(uint32_t reader_id, const TEE_UUID *uuid)
{
    if (reader_id >= READER_MAX) {
        tloge("reader id is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (reader_id == SCARD_MODE_MSP)
        return se_service_check_msp_permission(uuid);
    else if (reader_id < SCARD_MODE_MSP)
        return se_service_check_permission(uuid);
    else
        return TEE_SUCCESS;
}

static TEE_Result se_task_get_type(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                   uint32_t sndr_pid, const TEE_UUID *uuid)
{
    (void)sndr_pid;
    (void)uuid;
    (void)msg;

    if (g_se_type == SE_SRV_ERROR)
        g_se_type = scard_get_ese_type();
    rsp->data.type_rsp.type = g_se_type;
    rsp->data.ret = TEE_SUCCESS;

    return rsp->data.ret;
}

static TEE_Result handle_connect(uint64_t p_atr_shared, uint32_t *atr_len, uint32_t reader_id, const TEE_UUID *uuid)
{
    int32_t scard_ret;
    uint32_t vote_id;
    uint8_t *p_atr = NULL;
    uint32_t original_atr_len = *atr_len;

    p_atr = TEE_Malloc(original_atr_len, 0);
    if (p_atr == NULL) {
        tloge("Failed to malloc atr\n");
        return TEE_ERROR_OUT_OF_MEMORY;
    }

    if (reader_id == SCARD_MODE_INSE) {
        if (SE_getflag() == SE_CONNECT_FLAG) {
            tloge("SE had been connected\n");
            TEE_Free(p_atr);
            return TEE_ERROR_SESSION_MAXIMUM;
        }
        if (SE_setflag(SE_CONNECT_FLAG) == SE_SRV_ERROR) {
            tloge("set se flag failed\n");
            TEE_Free(p_atr);
            return TEE_ERROR_GENERIC;
        }
    }

    vote_id = get_vote_id(reader_id, uuid);
    scard_ret = scard_connect((int)reader_id, vote_id, p_atr, atr_len);
    if (scard_ret != SE_SRV_SUCCESS) {
        tloge("0x%x-0x%x-0x%x connect se failed:%d\n",
              uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, scard_ret);
        if (reader_id == SCARD_MODE_INSE)
            (void)SE_setflag(SE_DISCONNECT_FLAG);
        TEE_Free(p_atr);
        return (TEE_Result)scard_ret;
    }

    if (memcpy_s((uint8_t *)(uintptr_t)p_atr_shared, original_atr_len, p_atr, *atr_len) != EOK) {
        tloge("Failed to copy rsp\n");
        (void)scard_disconnect((int)reader_id, vote_id);
        if (reader_id == SCARD_MODE_INSE)
            (void)SE_setflag(SE_DISCONNECT_FLAG);
        TEE_Free(p_atr);
        return TEE_ERROR_SECURITY;
    }

    TEE_Free(p_atr);
    return TEE_SUCCESS;
}

static TEE_Result se_connect_info_update(uint32_t reader_id, uint32_t sndr_pid, const TEE_UUID *uuid)
{
    struct se_connect_info *se_connect_info_temp = NULL;
    struct se_connect_info *se_connect_info_tail = NULL;

    if (reader_id >= READER_MAX) {
        tloge("reader id is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    dlist_for_each_entry(se_connect_info_temp, &g_se_connect_info_head[reader_id], struct se_connect_info, list) {
        if (se_connect_info_temp->sndr_pid == sndr_pid) {
            se_connect_info_temp->connect_count++;
            sre_se_connect_info_write(reader_id, (uint8_t *)se_connect_info_temp, 1);
            return TEE_SUCCESS;
        }
    }
    se_connect_info_tail = TEE_Malloc(sizeof(*se_connect_info_tail), 0);
    if (se_connect_info_tail == NULL) {
        tloge("malloc se connect info failed\n");
        return TEE_ERROR_OUT_OF_MEMORY;
    }
    se_connect_info_tail->sndr_pid = sndr_pid;
    se_connect_info_tail->connect_count = 1;
    if (memcpy_s(&se_connect_info_tail->uuid, sizeof(se_connect_info_tail->uuid), uuid, sizeof(*uuid)) != EOK) {
        tloge("memcpy se connect info's uuid failed\n");
        TEE_Free(se_connect_info_tail);
        return TEE_ERROR_SECURITY;
    }
    dlist_insert_tail(&se_connect_info_tail->list, &g_se_connect_info_head[reader_id]);
    sre_se_connect_info_write(reader_id, (uint8_t *)se_connect_info_tail, 1);

    return TEE_SUCCESS;
}

static TEE_Result se_task_connect(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                  uint32_t sndr_pid, const TEE_UUID *uuid)
{
    uint64_t p_atr_shared = 0;
    uint32_t atr_len;
    uint32_t vote_id;

    rsp->data.ret = check_permission(msg->data.connect_msg.reader_id, uuid);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    if (msg->data.connect_msg.atr_len > APDU_LEN_MAX) {
        rsp->data.ret = TEE_ERROR_BAD_PARAMETERS;
        return rsp->data.ret;
    }

    if (se_srv_map_from_task(sndr_pid, msg->data.connect_msg.p_atr,
                             msg->data.connect_msg.atr_len, &p_atr_shared) != 0) {
        tloge("map buff from 0x%x fail\n", sndr_pid);
        rsp->data.ret = TEE_ERROR_GENERIC;
        goto connect_clean;
    }

    atr_len = msg->data.connect_msg.atr_len;
    rsp->data.ret = handle_connect(p_atr_shared, &atr_len,
                                   msg->data.connect_msg.reader_id, uuid);

    rsp->data.connect_rsp.atr_len = atr_len;

connect_clean:
    se_srv_task_unmap(p_atr_shared, msg->data.connect_msg.atr_len);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    rsp->data.ret = se_connect_info_update(msg->data.connect_msg.reader_id, sndr_pid, uuid);
    if (rsp->data.ret == TEE_SUCCESS) {
        tlogi("0x%x-0x%x-0x%x connect se %u\n",
            uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, msg->data.connect_msg.reader_id);
        return rsp->data.ret;
    }

    tloge("se connect info update failed, ret = 0x%x\n", rsp->data.ret);
    vote_id = get_vote_id(msg->data.connect_msg.reader_id, uuid);
    (void)scard_disconnect((int)msg->data.connect_msg.reader_id, vote_id);
    if (msg->data.connect_msg.reader_id == SCARD_MODE_INSE)
        (void)SE_setflag(SE_DISCONNECT_FLAG);
    return rsp->data.ret;
}

static struct se_connect_info *get_connect_info(const struct se_srv_msg_t *msg, uint32_t sndr_pid)
{
    struct se_connect_info *se_connect_info_temp = NULL;

    dlist_for_each_entry(se_connect_info_temp, &g_se_connect_info_head[msg->data.disconnect_msg.reader_id],
        struct se_connect_info, list) {
        if ((se_connect_info_temp)->sndr_pid != sndr_pid)
            continue;

        if ((se_connect_info_temp)->connect_count > 0)
            return se_connect_info_temp;

        break;
    }

    tloge("se %u has not been connected\n", msg->data.disconnect_msg.reader_id);
    return NULL;
}

static TEE_Result se_task_disconnect(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                     uint32_t sndr_pid, const TEE_UUID *uuid)
{
    int32_t scard_ret;
    uint32_t vote_id;
    struct se_connect_info *se_connect_info_temp = NULL;

    rsp->data.ret = check_permission(msg->data.disconnect_msg.reader_id, uuid);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;
    se_connect_info_temp = get_connect_info(msg, sndr_pid);
    if (se_connect_info_temp == NULL) {
        rsp->data.ret = TEE_ERROR_ACCESS_DENIED;
        return rsp->data.ret;
    }

    vote_id = get_vote_id(msg->data.disconnect_msg.reader_id, uuid);
    scard_ret = scard_disconnect((int)msg->data.disconnect_msg.reader_id, vote_id);
    if (scard_ret != SE_SRV_SUCCESS) {
        tloge("0x%x-0x%x-0x%x disconnect se failed:%d\n",
              uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, scard_ret);
        rsp->data.ret = (TEE_Result)scard_ret;
        return rsp->data.ret;
    }
    if (msg->data.disconnect_msg.reader_id == SCARD_MODE_INSE) {
        if (SE_setflag(SE_DISCONNECT_FLAG) == SE_SRV_ERROR) {
            tloge("set se flag failed\n");
            rsp->data.ret = TEE_ERROR_GENERIC;
            return rsp->data.ret;
        }
    }
    rsp->data.ret = TEE_SUCCESS;
    se_connect_info_temp->connect_count--;
    sre_se_connect_info_write(msg->data.disconnect_msg.reader_id, (uint8_t *)se_connect_info_temp, 1);
    if (se_connect_info_temp->connect_count == 0) {
        dlist_delete((struct dlist_node *)&se_connect_info_temp->list);
        TEE_Free(se_connect_info_temp);
        se_connect_info_temp = NULL;
    }
    tlogi("0x%x-0x%x-0x%x disconnect se %u\n",
        uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, msg->data.disconnect_msg.reader_id);
    return rsp->data.ret;
}

static TEE_Result se_sync_transmit(uint32_t reader_id,
                                   uint8_t *p_cmd, uint32_t cmd_len,
                                   uint8_t *p_rsp, uint32_t *rsp_len)
{
    int32_t scard_ret;

    scard_ret = scard_transmit((int)reader_id, p_cmd, cmd_len, p_rsp, rsp_len);
    if (scard_ret != SE_SRV_SUCCESS) {
        tloge("se transmit failed:%d\n", scard_ret);
        return (TEE_Result)scard_ret;
    }

    return TEE_SUCCESS;
}

static TEE_Result se_async_transmit(uint32_t reader_id,
                                    uint8_t *p_cmd, uint32_t cmd_len,
                                    uint8_t *p_rsp, uint32_t *rsp_len)
{
    TEE_Result ret;
    uint32_t sync_count = 0;
    int32_t scard_ret;

    scard_ret = scard_send((int)reader_id, p_cmd, cmd_len);
    if (scard_ret != SE_SRV_SUCCESS) {
        tloge("se send failed for scard send:%d\n", scard_ret);
        return (TEE_Result)scard_ret;
    }

    while (scard_get_status() != SCARD_STATUS_RECEIVE_READY) {
        ret = tee_msleep(ASYNC_SLICE);
        if (ret != TEE_SUCCESS) {
            tloge("tee wait occur some error=0x%x\n", ret);
            return ret;
        }

        sync_count++;
        tlogd("se srv transmit sync2 mode, loop time %u\n", sync_count);

        if (sync_count >= ASYNC_MAX_COUNT) {
            tloge("get receive after send command failed\n");
            return TEE_ERROR_TIMEOUT;
        }
    }

    scard_ret = scard_receive(p_rsp, rsp_len);
    if (scard_ret != SE_SRV_SUCCESS) {
        tloge("se task receive failed:%d\n", scard_ret);
        return (TEE_Result)scard_ret;
    }

    return TEE_SUCCESS;
}

static bool check_aid_status(uint32_t reader_id, const uint8_t *cmd, uint32_t cmd_len)
{
    uint8_t aid[AID_LEN_MAX] = {0};
    uint32_t aid_len;
    struct seaid_switch_srv_info *seaid_switch = NULL;

    (void)reader_id;
    if (cmd_len < APDU_CDATA || cmd_len > APDU_CDATA + AID_LEN_MAX) {
        tloge("cmd len is too short or too long\n");
        return false;
    }

    aid_len = cmd[APDU_LC];
    if (aid_len == 0)
        return true;
    if (cmd_len == APDU_CDATA) {
        tloge("cmd len and LC are not match\n");
        return false;
    }

    if (memcpy_s(aid, AID_LEN_MAX, &cmd[APDU_CDATA], aid_len) != EOK) {
        tloge("copy aid failed\n");
        return false;
    }

    dlist_for_each_entry(seaid_switch, &g_seaid_switch_head, struct seaid_switch_srv_info, list) {
        if (seaid_switch->seaid_switch.aid_len > AID_LEN_MAX)
            return false;
        if (seaid_switch->seaid_switch.aid[seaid_switch->seaid_switch.aid_len - 1] == '*') {
            if (seaid_switch->seaid_switch.aid_len - 1 > aid_len)
                continue;
            if (TEE_MemCompare(seaid_switch->seaid_switch.aid, aid, seaid_switch->seaid_switch.aid_len - 1) != 0)
                continue;
        } else {
            if (seaid_switch->seaid_switch.aid_len != aid_len)
                continue;
            if (TEE_MemCompare(seaid_switch->seaid_switch.aid, aid, seaid_switch->seaid_switch.aid_len) != 0)
                continue;
        }

        if (seaid_switch->seaid_switch.closed) {
            tloge("aid is closed\n");
            return false;
        } else {
            return true;
        }
    }

    tloge("aid not exist\n");
    return true;
}

static bool check_applet_accessibility(uint32_t reader_id, const uint8_t *cmd, uint32_t cmd_len)
{
    bool need_check = (reader_id == SCARD_MODE_INSE &&
                       (g_se_type == SCARD_MODE_INSE || g_se_type == SCARD_MODE_BOTH)) ||
                      (reader_id == SCARD_MODE_ESE && g_se_type == SCARD_MODE_ESE);

    if (!need_check)
        return true;

    if (g_se_deactive_flag) {
        tloge("se is deactivate\n");
        return false;
    }

    return check_aid_status(reader_id, cmd, cmd_len);
}

static TEE_Result check_apdus(uint32_t reader_id,
                              const uint8_t *cmd, uint32_t cmd_len,
                              uint8_t *rsp, uint32_t *rsp_len)
{
    /* Check if the command is SELECT or not */
    if (cmd[APDU_INS] != INS_SELECT)
        return TEE_SUCCESS;

    /* If SELECT, ask SEM_CONTROL_MODULE, to learn the SELECT can be processed or not */
    if (check_applet_accessibility(reader_id, cmd, cmd_len))
        return TEE_SUCCESS;

    /*
     * Come here, means SELECT without accessibility. Calling SE driver should be blocked outside.
     * Assign SW=0x8FFF's length.
     * If SEM_CONTROL_MODULE refuses this SELECT, return SW=0x8FFF.
     */
    if (memcpy_s(rsp, *rsp_len, g_buf_sw_refused, SW_GP_LEN) != EOK) {
        tloge("cpy response buffer failed\n");
        return TEE_ERROR_SECURITY;
    }
    *rsp_len = SW_GP_LEN;
    return TEE_ERROR_COMMUNICATION;
}

static TEE_Result se_common_transmit(uint32_t reader_id,
                                     uint8_t *p_cmd, uint32_t cmd_len,
                                     uint8_t *p_rsp, uint32_t *rsp_len)
{
    int32_t sync_mode;
    TEE_Result ret;

    ret = check_apdus(reader_id, p_cmd, cmd_len, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("se transmit failed for check apdus:0x%x\n", ret);
        return ret;
    }

    sync_mode = scard_support_mode((int)reader_id);
    if ((sync_mode == SCARD_MODE_SYNC) || (sync_mode == SCARD_MODE_ASYNC))
        return se_sync_transmit(reader_id, p_cmd, cmd_len, p_rsp, rsp_len);
    else if (sync_mode == SCARD_MODE_SYNC2)
        return se_async_transmit(reader_id, p_cmd, cmd_len, p_rsp, rsp_len);
    else
        tloge("invalid sync mode of se srv transmit, mode=%d\n", sync_mode);

    return TEE_ERROR_BAD_PARAMETERS;
}

static TEE_Result is_apdu_valid(uint8_t channel_id, uint32_t reader_id, uint32_t sndr_pid,
                                uint32_t cmd_len, uint32_t rsp_len)
{
    if (reader_id >= READER_MAX) {
        tloge("reader id is invalid\n");
        return TEE_ERROR_BAD_PARAMETERS;
    }

    if (sndr_pid != g_ta_channel[reader_id][channel_id])
        return TEE_ERROR_ACCESS_DENIED;

    if (cmd_len > APDU_LEN_MAX || cmd_len < APDU_LEN_MIN ||
        rsp_len > APDU_LEN_MAX || rsp_len < SW_GP_LEN)
        return TEE_ERROR_BAD_PARAMETERS;

    return TEE_SUCCESS;
}

static TEE_Result handle_transmit(uint64_t p_cmd_shared, uint32_t cmd_len,
                                  uint64_t p_rsp_shared, uint32_t *rsp_len,
                                  const struct channel_info_t *channel_info)
{
    TEE_Result ret;
    uint8_t *p_cmd = NULL;
    uint8_t *p_rsp = NULL;
    uint32_t original_rsp_len = *rsp_len;
    uint8_t real_channel_id;

    p_cmd = TEE_Malloc(cmd_len, 0);
    p_rsp = TEE_Malloc(original_rsp_len, 0);
    if (p_cmd == NULL || p_rsp == NULL) {
        ret = TEE_ERROR_OUT_OF_MEMORY;
        goto handle_transmit_clean;
    }

    (void)memcpy_s(p_cmd, cmd_len, (uint8_t *)(uintptr_t)p_cmd_shared, cmd_len);

    if (channel_info->reader_id == SCARD_MODE_SECURE_FLASH) {
        tlogd("secflash don't need to change channel id = 0x%x\n", p_cmd[APDU_CLA]);
    } else {
        if (channel_info->channel_id < LOGIC_CHANNEL_ID_OFFSET) {
            p_cmd[APDU_CLA] &= CLA_MASK_B1B2B7;
            real_channel_id = channel_info->channel_id;
        } else {
            p_cmd[APDU_CLA] &= CLA_MASK_B1B2B3B4B7;
            real_channel_id = (channel_info->channel_id - LOGIC_CHANNEL_ID_OFFSET) | GET_SEVENTH_BIT;
        }

        p_cmd[APDU_CLA] |= real_channel_id;
        tlogi("transmit channel id:0x%x\n", real_channel_id);
    }

    ret = se_common_transmit(channel_info->reader_id, p_cmd, cmd_len, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("se transmit failed:0x%x\n", ret);
        goto handle_transmit_clean;
    }

    if (memcpy_s((uint8_t *)(uintptr_t)p_rsp_shared, original_rsp_len, p_rsp, *rsp_len) != EOK) {
        ret = TEE_ERROR_SECURITY;
        goto handle_transmit_clean;
    }
    ret = TEE_SUCCESS;

handle_transmit_clean:
    TEE_Free(p_cmd);
    p_cmd = NULL;
    TEE_Free(p_rsp);
    return ret;
}

static TEE_Result se_task_transmit(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                   uint32_t sndr_pid, const TEE_UUID *uuid)
{
    uint64_t p_cmd_shared = 0;
    uint64_t p_rsp_shared = 0;
    uint32_t rsp_len;
    struct channel_info_t channel_info = {0};

    rsp->data.ret = check_permission(msg->data.transmit_msg.reader_id, uuid);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    rsp->data.ret = is_apdu_valid(msg->data.transmit_msg.channel_id, msg->data.transmit_msg.reader_id, sndr_pid,
                                  msg->data.transmit_msg.cmd_len, msg->data.transmit_msg.rsp_len);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    if (se_srv_map_from_task(sndr_pid, msg->data.transmit_msg.p_cmd,
                             msg->data.transmit_msg.cmd_len, &p_cmd_shared) != 0) {
        rsp->data.ret = TEE_ERROR_GENERIC;
        goto transmit_clean;
    }

    if (se_srv_map_from_task(sndr_pid, msg->data.transmit_msg.p_rsp,
                             msg->data.transmit_msg.rsp_len, &p_rsp_shared) != 0) {
        rsp->data.ret = TEE_ERROR_GENERIC;
        goto transmit_clean;
    }

    rsp_len = msg->data.transmit_msg.rsp_len;
    channel_info.reader_id = msg->data.open_logical_channel_msg.reader_id;
    channel_info.channel_id = msg->data.transmit_msg.channel_id;
    rsp->data.ret = handle_transmit(p_cmd_shared, msg->data.transmit_msg.cmd_len,
                                    p_rsp_shared, &rsp_len, &channel_info);

    rsp->data.transmit_rsp.rsp_len = rsp_len;

transmit_clean:
    se_srv_task_unmap(p_cmd_shared, msg->data.transmit_msg.cmd_len);
    se_srv_task_unmap(p_rsp_shared, msg->data.transmit_msg.rsp_len);
    return rsp->data.ret;
}

static TEE_Result is_success_response(const uint8_t *resp, uint32_t len, uint32_t original_rsp_len)
{
    uint32_t i;

    if (len < SW_GP_LEN || len > original_rsp_len) {
        tloge("response length is invalid %u\n", len);
        return TEE_ERROR_BAD_PARAMETERS;
    }
    if ((resp[len - SW_GP_LEN] == SW1_GP_SUCCESS) && (resp[len - SW2_GP_LEN] == SW2_GP_SUCCESS))
        return TEE_SUCCESS;

    tloge("response len is %u\n", len);
    for (i = 0; i < len; i++)
        tloge("0x%x\n", resp[i]);

    return TEE_ERROR_GENERIC;
}

static TEE_Result is_manage_success_response(const uint8_t *resp, uint32_t len, uint32_t original_rsp_len)
{
    TEE_Result ret;

    ret = is_success_response(resp, len, original_rsp_len);
    if (ret == TEE_ERROR_GENERIC) {
        ret |= (uint32_t)resp[len - SW_GP_LEN] << BYTE_LEN;
        ret |= resp[len - SW2_GP_LEN];
    }
    return ret;
}

static TEE_Result is_select_success_response(const uint8_t *resp, uint32_t len, uint32_t original_rsp_len)
{
    TEE_Result ret;

    ret = is_success_response(resp, len, original_rsp_len);
    if (ret == TEE_ERROR_GENERIC) {
        if ((resp[len - SW_GP_LEN] == SW1_GP_WARNING1) || (resp[len - SW_GP_LEN] == SW1_GP_WARNING2))
            return TEE_SUCCESS;

        ret |= (uint32_t)resp[len - SW_GP_LEN] << BYTE_LEN;
        ret |= resp[len - SW2_GP_LEN];
    }
    return ret;
}

static void write_channel_info_to_sys(uint32_t reader_id, uint8_t channel_id, uint32_t sndr_pid)
{
    g_ta_channel[reader_id][channel_id] = sndr_pid;
    sre_se_channel_info_write(reader_id, (uint32_t)channel_id, sndr_pid);
}

static TEE_Result handle_open_basic_channel(uint64_t se_aid_shared, uint32_t se_aid_len,
                                            uint64_t p_rsp_shared, uint32_t *rsp_len,
                                            uint32_t reader_id)
{
    TEE_Result ret;
    uint8_t *p_rsp = NULL;
    uint8_t *apdu_pkg = NULL;
    uint32_t apdu_len = APDU_CDATA + se_aid_len;
    uint32_t original_rsp_len = *rsp_len;

    apdu_pkg = TEE_Malloc(apdu_len, 0);
    p_rsp = TEE_Malloc(original_rsp_len, 0);
    if (apdu_pkg == NULL || p_rsp == NULL) {
        ret = TEE_ERROR_OUT_OF_MEMORY;
        goto handle_basic_channel_clean;
    }

    apdu_pkg[APDU_CLA] = CLA_BASIC_CHANNEL;
    apdu_pkg[APDU_INS] = INS_SELECT;
    apdu_pkg[APDU_P1] = P1_SELECT;
    apdu_pkg[APDU_P2] = P2_SELECT;
    apdu_pkg[APDU_LC] = (uint8_t)se_aid_len;
    if (se_aid_len != 0) {
        if (memcpy_s(&apdu_pkg[APDU_CDATA], apdu_len - APDU_CDATA,
                     (uint8_t *)(uintptr_t)se_aid_shared, se_aid_len) != EOK) {
            tloge("cpy aid failed\n");
            ret = TEE_ERROR_SECURITY;
            goto handle_basic_channel_clean;
        }
    }

    ret = se_common_transmit(reader_id, apdu_pkg, apdu_len, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("se transmit failed:0x%x\n", ret);
        goto handle_basic_channel_clean;
    }
    ret = is_select_success_response(p_rsp, *rsp_len, original_rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("open basic channel failed\n");
        goto handle_basic_channel_clean;
    }

    if (memcpy_s((uint8_t *)(uintptr_t)p_rsp_shared, original_rsp_len, p_rsp, *rsp_len) != EOK) {
        ret = TEE_ERROR_SECURITY;
        goto handle_basic_channel_clean;
    }
    ret = TEE_SUCCESS;

handle_basic_channel_clean:
    TEE_Free(apdu_pkg);
    apdu_pkg = NULL;
    TEE_Free(p_rsp);
    return ret;
}

static TEE_Result se_task_open_basic_channel(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                             uint32_t sndr_pid, const TEE_UUID *uuid)
{
    uint64_t se_aid_shared = 0;
    uint64_t p_rsp_shared = 0;
    uint32_t rsp_len;

    rsp->data.ret = check_permission(msg->data.open_basic_channel_msg.reader_id, uuid);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    if (g_ta_channel[msg->data.open_basic_channel_msg.reader_id][BASIC_CHANNEL_ID] != 0) {
        tloge("basic channel has been opened\n");
        rsp->data.ret = TEE_ERROR_ACCESS_CONFLICT;
        return rsp->data.ret;
    }

    if (msg->data.open_basic_channel_msg.se_aid_len > APDU_LEN_MAX - APDU_CDATA ||
        msg->data.open_basic_channel_msg.rsp_len > APDU_LEN_MAX ||
        msg->data.open_basic_channel_msg.rsp_len < SW_GP_LEN) {
        rsp->data.ret = TEE_ERROR_BAD_PARAMETERS;
        return rsp->data.ret;
    }

    if (msg->data.open_basic_channel_msg.se_aid_len != 0) {
        if (se_srv_map_from_task(sndr_pid, msg->data.open_basic_channel_msg.se_aid,
                                 msg->data.open_basic_channel_msg.se_aid_len, &se_aid_shared) != 0) {
            rsp->data.ret = TEE_ERROR_GENERIC;
            goto open_basic_channel_clean;
        }
    }

    if (se_srv_map_from_task(sndr_pid, msg->data.open_basic_channel_msg.p_rsp,
                             msg->data.open_basic_channel_msg.rsp_len, &p_rsp_shared) != 0) {
        rsp->data.ret = TEE_ERROR_GENERIC;
        goto open_basic_channel_clean;
    }

    rsp_len = msg->data.open_basic_channel_msg.rsp_len;
    rsp->data.ret = handle_open_basic_channel(se_aid_shared, msg->data.open_basic_channel_msg.se_aid_len,
                                              p_rsp_shared, &rsp_len,
                                              msg->data.open_basic_channel_msg.reader_id);
    if (rsp->data.ret == TEE_SUCCESS) {
        write_channel_info_to_sys(msg->data.open_basic_channel_msg.reader_id, BASIC_CHANNEL_ID, sndr_pid);
        tlogi("0x%x-0x%x-0x%x open basic channel\n", uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion);
    }
    rsp->data.open_basic_channel_rsp.rsp_len = rsp_len;
open_basic_channel_clean:
    se_srv_task_unmap(se_aid_shared, msg->data.open_basic_channel_msg.se_aid_len);
    se_srv_task_unmap(p_rsp_shared, msg->data.open_basic_channel_msg.rsp_len);
    return rsp->data.ret;
}

static TEE_Result manage_channel_open(uint32_t reader_id,
                                      uint8_t *p_rsp, uint32_t *rsp_len)
{
    TEE_Result ret;
    uint8_t manage_apdu_pkg[APDU_CDATA];
    uint32_t original_rsp_len = *rsp_len;

    if (reader_id == SCARD_MODE_SECURE_FLASH) {
        p_rsp[RSP_MANAGE_CHANNEL] = 1; /* secflash only support logical channel 1 */
        return TEE_SUCCESS;
    }
    manage_apdu_pkg[APDU_CLA] = CLA_MANAGE_CHANNEL;
    manage_apdu_pkg[APDU_INS] = INS_MANAGE_CHANNEL;
    manage_apdu_pkg[APDU_P1] = P1_MANAGE_CHANNEL_OPEN;
    manage_apdu_pkg[APDU_P2] = P2_MANAGE_CHANNEL_OPEN;
    manage_apdu_pkg[APDU_LC] = LE_MANAGE_CHANNEL_OPEN;

    ret = se_common_transmit(reader_id, manage_apdu_pkg, APDU_CDATA, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS)
        return ret;

    ret = is_manage_success_response(p_rsp, *rsp_len, original_rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("manage channel failed\n");
        return ret;
    }

    return TEE_SUCCESS;
}

static TEE_Result manage_channel_close(uint32_t reader_id, uint8_t logic_channel_id)
{
    uint8_t manage_apdu_pkg[APDU_LC];
    uint8_t p_rsp[APDU_MANAGE_CHANNEL_RESP_LEN] = {0};
    uint32_t rsp_len = APDU_MANAGE_CHANNEL_RESP_LEN;

    if (reader_id == SCARD_MODE_SECURE_FLASH)
        return TEE_SUCCESS;

    manage_apdu_pkg[APDU_CLA] = CLA_MANAGE_CHANNEL;
    manage_apdu_pkg[APDU_INS] = INS_MANAGE_CHANNEL;
    manage_apdu_pkg[APDU_P1] = P1_MANAGE_CHANNEL_CLOSE;
    manage_apdu_pkg[APDU_P2] = logic_channel_id;

    return se_common_transmit(reader_id, manage_apdu_pkg, APDU_LC, p_rsp, &rsp_len);
}

static TEE_Result select_channel(uint64_t se_aid_shared, uint32_t se_aid_len,
                                 uint8_t *p_rsp, uint32_t *rsp_len,
                                 const struct channel_info_t *channel_info)
{
    TEE_Result ret;
    uint8_t *apdu_pkg = NULL;
    uint32_t apdu_len;
    uint8_t real_channel_id;
    uint32_t original_rsp_len = *rsp_len;

    apdu_len = APDU_CDATA + se_aid_len;
    apdu_pkg = TEE_Malloc(apdu_len, 0);
    if (apdu_pkg == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;

    if (channel_info->channel_id < LOGIC_CHANNEL_ID_OFFSET)
        real_channel_id = channel_info->channel_id;
    else
        real_channel_id = (channel_info->channel_id - LOGIC_CHANNEL_ID_OFFSET) | GET_SEVENTH_BIT;

    apdu_pkg[APDU_CLA] = real_channel_id;
    apdu_pkg[APDU_INS] = INS_SELECT;
    apdu_pkg[APDU_P1] = P1_SELECT;
    apdu_pkg[APDU_P2] = P2_SELECT;
    apdu_pkg[APDU_LC] = (uint8_t)se_aid_len;
    if (se_aid_len != 0) {
        if (memcpy_s(&apdu_pkg[APDU_CDATA], apdu_len - APDU_CDATA,
                     (uint8_t *)(uintptr_t)se_aid_shared, se_aid_len) != EOK) {
            tloge("cpy aid failed\n");
            ret = TEE_ERROR_SECURITY;
            goto select_channel_clean;
        }
    }

    ret = se_common_transmit(channel_info->reader_id, apdu_pkg, apdu_len, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("se transmit failed:0x%x\n", ret);
        goto select_channel_clean;
    }

    ret = is_select_success_response(p_rsp, *rsp_len, original_rsp_len);
    if (ret != TEE_SUCCESS) {
        tloge("select channel failed\n");
        goto select_channel_clean;
    }

select_channel_clean:
    TEE_Free(apdu_pkg);
    return ret;
}

static TEE_Result handle_open_logical_channel(uint64_t se_aid_shared, uint32_t se_aid_len,
                                              uint64_t p_rsp_shared, uint32_t *rsp_len,
                                              struct channel_info_t *channel_info)
{
    TEE_Result ret;
    uint8_t *p_rsp = NULL;
    uint32_t original_rsp_len = *rsp_len;

    p_rsp = TEE_Malloc(original_rsp_len, 0);
    if (p_rsp == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;

    ret = manage_channel_open(channel_info->reader_id, p_rsp, rsp_len);
    if (ret != TEE_SUCCESS)
        goto handle_logical_channel_clean;

    channel_info->channel_id = p_rsp[RSP_MANAGE_CHANNEL];
    *rsp_len = original_rsp_len;
    ret = select_channel(se_aid_shared, se_aid_len, p_rsp, rsp_len, channel_info);
    if (ret != TEE_SUCCESS)
        goto close_logical_channel_clean;

    if (memcpy_s((uint8_t *)(uintptr_t)p_rsp_shared, original_rsp_len, p_rsp, *rsp_len) != EOK) {
        ret = TEE_ERROR_SECURITY;
        goto close_logical_channel_clean;
    }
    TEE_Free(p_rsp);
    return TEE_SUCCESS;

close_logical_channel_clean:
    if (manage_channel_close(channel_info->reader_id, channel_info->channel_id) != TEE_SUCCESS)
        tlogd("channel close failed\n");

handle_logical_channel_clean:
    TEE_Free(p_rsp);
    return ret;
}

static TEE_Result is_logical_channel_available(uint32_t reader_id)
{
    uint8_t logic_channel_id;

    for (logic_channel_id = 1; logic_channel_id < LOGICAL_CHANNEL_MAX; logic_channel_id++) {
        if (g_ta_channel[reader_id][logic_channel_id] == 0)
            break;
    }
    if (logic_channel_id == LOGICAL_CHANNEL_MAX) {
        tloge("no more logical channel available\n");
        return TEE_ERROR_SESSION_MAXIMUM;
    }

    return TEE_SUCCESS;
}

static TEE_Result se_task_open_logical_channel(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                               uint32_t sndr_pid, const TEE_UUID *uuid)
{
    uint64_t se_aid_shared = 0;
    uint64_t p_rsp_shared = 0;
    uint8_t logic_channel_id;
    uint32_t reader_id = msg->data.open_logical_channel_msg.reader_id;
    struct channel_info_t channel_info = {0};
    uint32_t rsp_len;

    rsp->data.ret = check_permission(reader_id, uuid);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    rsp->data.ret = is_logical_channel_available(reader_id);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    if (msg->data.open_logical_channel_msg.se_aid_len > APDU_LEN_MAX - APDU_CDATA ||
        msg->data.open_logical_channel_msg.rsp_len > APDU_LEN_MAX ||
        msg->data.open_logical_channel_msg.rsp_len < SW_GP_LEN) {
        rsp->data.ret = TEE_ERROR_BAD_PARAMETERS;
        return rsp->data.ret;
    }

    if (msg->data.open_logical_channel_msg.se_aid_len != 0) {
        if (se_srv_map_from_task(sndr_pid, msg->data.open_logical_channel_msg.se_aid,
                                 msg->data.open_logical_channel_msg.se_aid_len, &se_aid_shared) != 0) {
            rsp->data.ret = TEE_ERROR_GENERIC;
            goto open_logical_channel_clean;
        }
    }

    if (se_srv_map_from_task(sndr_pid, msg->data.open_logical_channel_msg.p_rsp,
                             msg->data.open_logical_channel_msg.rsp_len, &p_rsp_shared) != 0) {
        rsp->data.ret = TEE_ERROR_GENERIC;
        goto open_logical_channel_clean;
    }

    rsp_len = msg->data.open_logical_channel_msg.rsp_len;
    channel_info.reader_id = msg->data.open_logical_channel_msg.reader_id;
    rsp->data.ret = handle_open_logical_channel(se_aid_shared, msg->data.open_logical_channel_msg.se_aid_len,
        p_rsp_shared, &rsp_len, &channel_info);
    if (rsp->data.ret == TEE_SUCCESS) {
        logic_channel_id = channel_info.channel_id;
        rsp->data.open_logical_channel_rsp.logic_channel_id = logic_channel_id;
        write_channel_info_to_sys(reader_id, logic_channel_id, sndr_pid);
        tlogi("0x%x-0x%x-0x%x open logic channel, id = 0x%x\n",
              uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, logic_channel_id);
    }
    rsp->data.open_logical_channel_rsp.rsp_len = rsp_len;
open_logical_channel_clean:
    se_srv_task_unmap(se_aid_shared, msg->data.open_logical_channel_msg.se_aid_len);
    se_srv_task_unmap(p_rsp_shared, msg->data.open_logical_channel_msg.rsp_len);
    return rsp->data.ret;
}

static TEE_Result se_task_close_channel(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                        uint32_t sndr_pid, const TEE_UUID *uuid)
{
    uint8_t channel_id = msg->data.close_channel_msg.channel_id;
    uint32_t reader_id = msg->data.close_channel_msg.reader_id;

    rsp->data.ret = check_permission(reader_id, uuid);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    rsp->data.ret = is_apdu_valid(channel_id, reader_id, sndr_pid,
                                  APDU_LC, APDU_MANAGE_CHANNEL_RESP_LEN);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    if (channel_id == 0) {
        write_channel_info_to_sys(reader_id, BASIC_CHANNEL_ID, 0);
        rsp->data.ret = TEE_SUCCESS;
        tlogi("0x%x-0x%x-0x%x close basic channel\n", uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion);
        return rsp->data.ret;
    }

    rsp->data.ret = manage_channel_close(reader_id, channel_id);
    if (rsp->data.ret == TEE_SUCCESS)
        write_channel_info_to_sys(reader_id, channel_id, 0);
    tlogi("0x%x-0x%x-0x%x close logic channel, id = 0x%x\n",
          uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion, channel_id);

    return rsp->data.ret;
}

static TEE_Result handle_select_channel(uint64_t se_aid_shared, uint32_t se_aid_len,
                                        uint64_t p_rsp_shared, uint32_t *rsp_len,
                                        const struct channel_info_t *channel_info)
{
    TEE_Result ret;
    uint8_t *p_rsp = NULL;
    uint32_t original_rsp_len = *rsp_len;

    p_rsp = TEE_Malloc(original_rsp_len, 0);
    if (p_rsp == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;

    ret = select_channel(se_aid_shared, se_aid_len, p_rsp, rsp_len, channel_info);
    if (ret != TEE_SUCCESS) {
        tloge("se select failed:0x%x\n", ret);
        goto handle_select_channel_clean;
    }

    if (memcpy_s((uint8_t *)(uintptr_t)p_rsp_shared, original_rsp_len, p_rsp, *rsp_len) != EOK) {
        ret = TEE_ERROR_SECURITY;
        goto handle_select_channel_clean;
    }
    ret = TEE_SUCCESS;

handle_select_channel_clean:
    TEE_Free(p_rsp);
    return ret;
}

static TEE_Result se_task_select_channel(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                         uint32_t sndr_pid, const TEE_UUID *uuid)
{
    uint64_t se_aid_shared = 0;
    uint64_t p_rsp_shared = 0;
    uint32_t rsp_len;
    struct channel_info_t channel_info = {0};

    rsp->data.ret = check_permission(msg->data.select_channel_msg.reader_id, uuid);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    rsp->data.ret = is_apdu_valid(msg->data.select_channel_msg.channel_id, msg->data.select_channel_msg.reader_id,
        sndr_pid, APDU_CDATA + msg->data.select_channel_msg.se_aid_len, msg->data.select_channel_msg.rsp_len);
    if (rsp->data.ret != TEE_SUCCESS)
        return rsp->data.ret;

    if (msg->data.select_channel_msg.se_aid_len != 0) {
        if (se_srv_map_from_task(sndr_pid, msg->data.select_channel_msg.se_aid,
                                 msg->data.select_channel_msg.se_aid_len, &se_aid_shared) != 0) {
            rsp->data.ret = TEE_ERROR_GENERIC;
            goto select_channel_clean;
        }
    }

    if (se_srv_map_from_task(sndr_pid, msg->data.select_channel_msg.p_rsp,
                             msg->data.select_channel_msg.rsp_len, &p_rsp_shared) != 0) {
        rsp->data.ret = TEE_ERROR_GENERIC;
        goto select_channel_clean;
    }

    rsp_len = msg->data.select_channel_msg.rsp_len;
    channel_info.reader_id = msg->data.select_channel_msg.reader_id;
    channel_info.channel_id = msg->data.select_channel_msg.channel_id;
    rsp->data.ret = handle_select_channel(se_aid_shared, msg->data.select_channel_msg.se_aid_len,
                                          p_rsp_shared, &rsp_len, &channel_info);
    rsp->data.select_channel_rsp.rsp_len = rsp_len;
select_channel_clean:
    se_srv_task_unmap(se_aid_shared, msg->data.select_channel_msg.se_aid_len);
    se_srv_task_unmap(p_rsp_shared, msg->data.select_channel_msg.rsp_len);
    return rsp->data.ret;
}

static void clean_channel_info(uint32_t reader_id, uint32_t taskid)
{
    uint8_t logic_channel_id;

    if (g_ta_channel[reader_id][BASIC_CHANNEL_ID] == taskid) {
        write_channel_info_to_sys(reader_id, BASIC_CHANNEL_ID, 0);
        tlogi("free caller close basic channel\n");
    }
    for (logic_channel_id = 1; logic_channel_id < LOGICAL_CHANNEL_MAX; logic_channel_id++) {
        if (g_ta_channel[reader_id][logic_channel_id] != taskid)
            continue;

        if (manage_channel_close(reader_id, logic_channel_id) != TEE_SUCCESS)
            tlogd("channel close failed\n");
        tlogi("free caller close logic channel, id = 0x%x\n", logic_channel_id);

        write_channel_info_to_sys(reader_id, logic_channel_id, 0);
    }
}

static void clean_connect_info(uint32_t reader_id, uint32_t taskid)
{
    struct se_connect_info *se_connect_info_temp = NULL;
    uint32_t vote_id;

    if (reader_id == SCARD_MODE_INSE)
        (void)SE_setflag(SE_DISCONNECT_FLAG);
    dlist_for_each_entry(se_connect_info_temp, &g_se_connect_info_head[reader_id], struct se_connect_info, list) {
        if (se_connect_info_temp->sndr_pid != taskid)
            continue;

        vote_id = get_vote_id(reader_id, &se_connect_info_temp->uuid);
        for (; se_connect_info_temp->connect_count > 0; se_connect_info_temp->connect_count--) {
            if (scard_disconnect((int)reader_id, vote_id) != SE_SRV_SUCCESS)
                tloge("free caller disconnect se %u failed\n", reader_id);
        }
        tlogi("free caller 0x%x-0x%x-0x%x disconnect se %u\n",
            se_connect_info_temp->uuid.timeLow, se_connect_info_temp->uuid.timeMid,
            se_connect_info_temp->uuid.timeHiAndVersion, reader_id);
        sre_se_connect_info_write(reader_id, (uint8_t *)se_connect_info_temp, 1);
        dlist_delete((struct dlist_node *)&se_connect_info_temp->list);
        TEE_Free(se_connect_info_temp);
        se_connect_info_temp = NULL;
        break;
    }
}

TEE_Result se_task_free_caller(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
    const TEE_UUID *uuid)
{
    uint32_t reader_id;
    TEE_UUID gtask_uuid = TEE_SERVICE_GLOBAL;

    if (TEE_MemCompare(uuid, &gtask_uuid, sizeof(*uuid)) != 0) {
        tloge("sender is not gtask\n");
        rsp->data.ret = TEE_ERROR_ACCESS_DENIED;
        return rsp->data.ret;
    }

    for (reader_id = 0; reader_id < READER_MAX; reader_id++) {
        clean_channel_info(reader_id, msg->data.reg_ta_info_msg.taskid);
        clean_connect_info(reader_id, msg->data.reg_ta_info_msg.taskid);
    }
    rsp->data.ret = TEE_SUCCESS;
    return rsp->data.ret;
}

static TEE_Result se_task_get_msp_status(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                         uint32_t sndr_pid, const TEE_UUID *uuid)
{
    (void)msg;
    (void)sndr_pid;
    (void)uuid;

    rsp->data.msp_status_rsp.msp_status = is_msp_enable();
    rsp->data.ret = TEE_SUCCESS;

    return rsp->data.ret;
}

static TEE_Result se_task_get_sec_flash_status(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                               uint32_t sndr_pid, const TEE_UUID *uuid)
{
    (void)msg;
    (void)sndr_pid;
    (void)uuid;

    rsp->data.sec_flash_status_rsp.sec_flash_status = is_sec_flash_enable();
    rsp->data.ret = TEE_SUCCESS;

    return rsp->data.ret;
}

static TEE_Result handle_set_aid(uint64_t seaid_list_shared, uint32_t seaid_list_len, uint32_t seaid_msg_len)
{
    struct seaid_switch_info *seaid_list = NULL;
    struct seaid_switch_srv_info *seaid_switch_srv = NULL;
    struct seaid_switch_srv_info *seaid_switch_srv_temp = NULL;
    uint32_t aid_index;
    bool need_update_drv = false;
    TEE_Result ret = TEE_SUCCESS;

    seaid_list = TEE_Malloc(seaid_msg_len, 0);
    if (seaid_list == NULL)
        return TEE_ERROR_OUT_OF_MEMORY;

    (void)memcpy_s(seaid_list, seaid_msg_len,
                   (struct seaid_switch_info *)(uintptr_t)seaid_list_shared, seaid_msg_len);

    /* If adding a node fails, the previously added node will not be freed */
    for (aid_index = 0; aid_index < seaid_list_len; aid_index++) {
        seaid_switch_srv = TEE_Malloc(sizeof(*seaid_switch_srv), 0);
        if (seaid_switch_srv == NULL) {
            ret = TEE_ERROR_OUT_OF_MEMORY;
            break;
        }

        if (memcpy_s(seaid_switch_srv->seaid_switch.aid, AID_LEN_MAX,
                     seaid_list[aid_index].aid, seaid_list[aid_index].aid_len) != EOK) {
            tloge("cpy seaid switch failed\n");
            TEE_Free(seaid_switch_srv);
            seaid_switch_srv = NULL;
            ret = TEE_ERROR_SECURITY;
            break;
        }
        seaid_switch_srv->seaid_switch.aid_len = seaid_list[aid_index].aid_len;
        seaid_switch_srv->seaid_switch.closed = seaid_list[aid_index].closed;

        dlist_for_each_entry(seaid_switch_srv_temp, &g_seaid_switch_head, struct seaid_switch_srv_info, list) {
            if (seaid_switch_srv_temp->seaid_switch.aid_len != seaid_switch_srv->seaid_switch.aid_len)
                continue;

            if (TEE_MemCompare(seaid_switch_srv_temp->seaid_switch.aid, seaid_switch_srv->seaid_switch.aid,
                               seaid_switch_srv->seaid_switch.aid_len) != 0)
                continue;

            seaid_switch_srv_temp->seaid_switch.closed = seaid_switch_srv->seaid_switch.closed;
            TEE_Free(seaid_switch_srv);
            seaid_switch_srv = NULL;
            break;
        }
        if (seaid_switch_srv != NULL)
            dlist_insert_tail(&seaid_switch_srv->list, &g_seaid_switch_head);
        need_update_drv = true;
    }

    if (need_update_drv)
        sre_seaid_switch_write((uint8_t *)seaid_list, aid_index);
    TEE_Free(seaid_list);
    return ret;
}

static TEE_Result se_task_set_aid(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                  uint32_t sndr_pid, const TEE_UUID *uuid)
{
    uint64_t seaid_list_shared = 0;
    uint32_t seaid_list_len = msg->data.set_aid_msg.seaid_list_len;
    uint32_t seaid_msg_len;
    TEE_UUID sem_uuid = TEE_SERVICE_SEM;

    if (TEE_MemCompare(uuid, &sem_uuid, sizeof(*uuid)) != 0) {
        tloge("sender is not sem\n");
        rsp->data.ret = TEE_ERROR_ACCESS_DENIED;
        return rsp->data.ret;
    }

    if (seaid_list_len == 0 || seaid_list_len > SEAID_LIST_LEN_MAX) {
        tloge("params is invalid\n");
        rsp->data.ret = TEE_ERROR_BAD_PARAMETERS;
        return rsp->data.ret;
    }

    seaid_msg_len = seaid_list_len * sizeof(struct seaid_switch_info);
    if (se_srv_map_from_task(sndr_pid, msg->data.set_aid_msg.seaid_list,
                             seaid_msg_len, &seaid_list_shared) != 0) {
        rsp->data.ret = TEE_ERROR_GENERIC;
        goto set_aid_clean;
    }

    rsp->data.ret = handle_set_aid(seaid_list_shared, seaid_list_len, seaid_msg_len);
set_aid_clean:
    se_srv_task_unmap(seaid_list_shared, seaid_msg_len);
    return rsp->data.ret;
}

static TEE_Result se_task_set_deactive(const struct se_srv_msg_t *msg, struct se_srv_rsp_t *rsp,
                                       uint32_t sndr_pid, const TEE_UUID *uuid)
{
    TEE_UUID sem_uuid = TEE_SERVICE_SEM;

    (void)sndr_pid;
    (void)uuid;

    if (TEE_MemCompare(uuid, &sem_uuid, sizeof(*uuid)) != 0) {
        tloge("sender is not sem\n");
        rsp->data.ret = TEE_ERROR_ACCESS_DENIED;
        return rsp->data.ret;
    }

    g_se_deactive_flag = msg->data.set_deactive_msg.deactive;
    if (g_se_deactive_flag)
        sre_se_deactive_write(1);
    else
        sre_se_deactive_write(0);

    rsp->data.ret = TEE_SUCCESS;

    return rsp->data.ret;
}

static const struct cmd_check_config_s g_cmd_check_config[] = {
    { CMD_SESRV_GET_ESE_TYPE,         se_task_get_type },
    { CMD_SESRV_CONNECT,              se_task_connect },
    { CMD_SESRV_DISCONNECT,           se_task_disconnect },
    { CMD_SESRV_TRANSMIT,             se_task_transmit },
    { CMD_SESRV_OPEN_BASIC_CHANNEL,   se_task_open_basic_channel },
    { CMD_SESRV_OPEN_LOGICAL_CHANNEL, se_task_open_logical_channel },
    { CMD_SESRV_CLOSE_CHANNEL,        se_task_close_channel },
    { CMD_SESRV_SELECT_CHANNEL,       se_task_select_channel },
    { CMD_SESRV_GET_MSP_STATUS,       se_task_get_msp_status },
    { CMD_SESRV_GET_SEC_FLASH_STATUS, se_task_get_sec_flash_status },
    { CMD_SESRV_SET_AID,              se_task_set_aid },
    { CMD_SESRV_SET_DEACTIVE,         se_task_set_deactive },
};
#define CMD_COUNT (sizeof(g_cmd_check_config) / sizeof(g_cmd_check_config[0]))

static void handle_cmd(const struct se_srv_msg_t *msg, uint32_t sndr_pid,
    const TEE_UUID *uuid, struct se_srv_rsp_t *rsp)
{
    uint32_t cmd_id;
    uint32_t i;

    rsp->data.ret = TEE_ERROR_GENERIC;
    cmd_id = msg->header.send.msg_id;

    for (i = 0; i < CMD_COUNT; i++) {
        if ((cmd_id != g_cmd_check_config[i].cmd_id) || (g_cmd_check_config[i].check_func == NULL))
            continue;
        rsp->data.ret = g_cmd_check_config[i].check_func(msg, rsp, sndr_pid, uuid);
        if (rsp->data.ret != TEE_SUCCESS)
            tloge("cmd 0x%x error, ret = 0x%x\n", cmd_id, rsp->data.ret);
        break;
    }
    if (i == CMD_COUNT)
        tloge("not support the cmd id 0x%x\n", cmd_id);
}

static void se_connect_info_init(void)
{
    uint32_t reader_id, i;
    struct se_connect_info se_sre_connect_info_temp[LOGICAL_CHANNEL_MAX];
    uint32_t se_connect_info_len;
    struct se_connect_info *se_connect_info_tail = NULL;

    (void)memset_s(se_sre_connect_info_temp, LOGICAL_CHANNEL_MAX * sizeof(se_sre_connect_info_temp[0]),
        0, LOGICAL_CHANNEL_MAX * sizeof(se_sre_connect_info_temp[0]));
    for (reader_id = 0; reader_id < READER_MAX; reader_id++) {
        dlist_init(&g_se_connect_info_head[reader_id]);
        se_connect_info_len = LOGICAL_CHANNEL_MAX;
        sre_se_connect_info_read(reader_id, (uint8_t *)se_sre_connect_info_temp, &se_connect_info_len);

        if (reader_id == SCARD_MODE_INSE && se_connect_info_len != 0) {
            if (SE_getflag() == SE_CONNECT_FLAG)
                tloge("SE had been connected\n");
            else if (SE_setflag(SE_CONNECT_FLAG) == SE_SRV_ERROR)
                tloge("set se flag failed\n");
        }
        for (i = 0; i < se_connect_info_len; i++) {
            se_connect_info_tail = TEE_Malloc(sizeof(*se_connect_info_tail), 0);
            /* buffer malloced before don't be freed, because here want to recover previous info as much as possible */
            if (se_connect_info_tail == NULL) {
                tloge("malloc se connect info failed\n");
                return;
            }
            if (memcpy_s(&(se_connect_info_tail->uuid), sizeof(se_connect_info_tail->uuid),
                         &(se_sre_connect_info_temp[i].uuid), sizeof(se_sre_connect_info_temp[i].uuid)) != EOK) {
                tloge("memcpy se connect info failed\n");
                TEE_Free(se_connect_info_tail);
                return;
            }
            se_connect_info_tail->sndr_pid = se_sre_connect_info_temp[i].sndr_pid;
            se_connect_info_tail->connect_count = se_sre_connect_info_temp[i].connect_count;
            dlist_insert_tail(&se_connect_info_tail->list, &g_se_connect_info_head[reader_id]);
        }
    }
}

static void se_channel_info_init(void)
{
    uint32_t i;
    uint32_t cnt;
    for (i = 0; i < READER_MAX; i++) {
        cnt = LOGICAL_CHANNEL_MAX;
        sre_se_channel_info_read(i, g_ta_channel[i], &cnt);
    }
}

static void se_aid_info_init(void)
{
    uint32_t seaid_list_len = 0;
    struct seaid_switch_info *seaid_list = NULL;
    struct seaid_switch_srv_info *seaid_switch_srv = NULL;
    uint32_t aid_index;
    uint32_t sre_deactive_flag = 0;

    sre_se_deactive_read(&sre_deactive_flag);
    if (sre_deactive_flag != 0)
        g_se_deactive_flag = true;

    dlist_init(&g_seaid_switch_head);
    sre_seaid_list_len_read(&seaid_list_len);
    seaid_list = TEE_Malloc(seaid_list_len * sizeof(*seaid_list), 0);
    if (seaid_list == NULL)
        return;
    sre_seaid_switch_read((uint8_t *)seaid_list, seaid_list_len);

    for (aid_index = 0; aid_index < seaid_list_len; aid_index++) {
        seaid_switch_srv = TEE_Malloc(sizeof(*seaid_switch_srv), 0);
        if (seaid_switch_srv == NULL)
            goto se_aid_init_clean;

        if (memcpy_s(seaid_switch_srv->seaid_switch.aid, AID_LEN_MAX,
                     seaid_list[aid_index].aid, seaid_list[aid_index].aid_len) != EOK) {
            TEE_Free(seaid_switch_srv);
            seaid_switch_srv = NULL;
            goto se_aid_init_clean;
        }
        seaid_switch_srv->seaid_switch.aid_len = seaid_list[aid_index].aid_len;
        seaid_switch_srv->seaid_switch.closed = seaid_list[aid_index].closed;
        dlist_insert_tail(&seaid_switch_srv->list, &g_seaid_switch_head);
    }

se_aid_init_clean:
    TEE_Free(seaid_list);
}

void se_service_info_init(void)
{
    se_connect_info_init();
    se_channel_info_init();
    se_aid_info_init();
}

void se_service_cmd(struct se_srv_msg_t *msg, TEE_UUID *uuid, uint32_t sndr_pid, struct se_srv_rsp_t *rsp)
{
    if (rsp == NULL)
        return;

    if (msg == NULL || uuid == NULL) {
        rsp->data.ret = TEE_ERROR_GENERIC;
        return;
    }

    handle_cmd(msg, sndr_pid, uuid, rsp);
}
